/* pshm_create.c

   Create a POSIX shared memory object with specified size and permissions.

   Usage as shown in usageError().
*/
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static void usageError(const char *progName) {
  fprintf(stderr, "Usage: %s [-cx] shm-name size [octal-perms]\n", progName);
  fprintf(stderr, "    -c   Create shared memory (O_CREAT)\n");
  fprintf(stderr, "    -x   Create exclusively (O_EXCL)\n");
  exit(EXIT_FAILURE);
}

static void errExit(char *msg) {
  perror(msg);
  exit(EXIT_FAILURE);
}

int main(int argc, char *argv[]) {
  int flags, opt, fd;
  mode_t perms;
  size_t size;
  void *addr;

  flags = O_RDWR;
  while ((opt = getopt(argc, argv, "cx")) != -1) {
    switch (opt) {
      case 'c':
        flags |= O_CREAT;
        break;
      case 'x':
        flags |= O_EXCL;
        break;
      default:
        usageError(argv[0]);
    }
  }

  if (optind + 1 >= argc) usageError(argv[0]);

  size = strtol(argv[optind + 1], NULL, 10);
  perms = (argc <= optind + 2) ? (S_IRUSR | S_IWUSR)
                               : strtol(argv[optind + 2], NULL, 10);

  /* Create shared memory object and set its size */
  fd = shm_open(argv[optind], flags, perms);
  if (fd == -1) errExit("shm_open");

  if (ftruncate(fd, size) == -1) errExit("ftruncate");

  /* Map shared memory object */

  addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  if (addr == MAP_FAILED) errExit("mmap");

  exit(EXIT_SUCCESS);
}